//  chrono_io
//
//  (C) Copyright Howard Hinnant
//  Use, modification and distribution are subject to the Boost Software License,
//  Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt).

#ifndef _CHRONO_IO
#define _CHRONO_IO

/*

    chrono_io synopsis

#include <chrono>
#include <ratio_io>

namespace std
{
namespace chrono
{

enum duration_style {prefix, symbol};
enum timezone {utc, local};

// facets

class durationpunct
    : public locale::facet
{
public:
    static locale::id id;

    explicit durationpunct(size_t refs = 0);
    explicit durationpunct(duration_style fmt, size_t refs = 0);
    
    bool is_symbol_name() const noexcept;
    bool is_prefix_name() const noexcept;
};

template <class charT>
class timepunct
    : public locale::facet
{
public:
    typedef basic_string<charT> string_type;

    static locale::id id;

    explicit timepunct(size_t refs = 0);
    timepunct(timezone tz, string_type fmt, size_t refs = 0);

    const string_type& fmt() const noexcept;
    std::chrono::timezone timezone() const noexcept;
};

// manipulators

class duration_fmt
{
public:
    explicit duration_fmt(duration_style f) noexcept;
    explicit operator duration_style() const noexcept;
};

unspecified time_fmt(timezone tz);
template<class charT>
    unspecified time_fmt(timezone tz, basic_string<charT> fmt);
template<class charT>
    unspecified time_fmt(timezone tz, const charT* fmt);

template<class charT, class traits>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, duration_fmt d);

template<class charT, class traits>
std::basic_istream<charT, traits>&
operator>>(std::basic_istream<charT, traits>& is, duration_fmt d);

// duration I/O

template <class charT, class Traits, class Rep, class Period>
    basic_ostream<charT, Traits>&
    operator<<(basic_ostream<charT, Traits>& os, const duration<Rep, Period>& d);

template <class charT, class Traits, class Rep, class Period>
    basic_istream<charT, Traits>&
    operator>>(basic_istream<charT, Traits>& is, duration<Rep, Period>& d);

// system_clock I/O

template <class charT, class Traits, class Duration>
    basic_ostream<charT, Traits>&
    operator<<(basic_ostream<charT, Traits>& os,
               const time_point<system_clock, Duration>& tp);

template <class charT, class Traits, class Duration>
    basic_istream<charT, Traits>&
    operator>>(basic_istream<charT, Traits>& is,
               time_point<system_clock, Duration>& tp);

// steady_clock I/O

template <class charT, class Traits, class Duration>
    basic_ostream<charT, Traits>&
    operator<<(basic_ostream<charT, Traits>& os,
               const time_point<steady_clock, Duration>& tp);

template <class charT, class Traits, class Duration>
    basic_istream<charT, Traits>&
    operator>>(basic_istream<charT, Traits>& is,
               time_point<steady_clock, Duration>& tp);

// high_resolution_clock I/O

template <class charT, class Traits, class Duration>
    basic_ostream<charT, Traits>&
    operator<<(basic_ostream<charT, Traits>& os,
               const time_point<high_resolution_clock, Duration>& tp);

template <class charT, class Traits, class Duration>
    basic_istream<charT, Traits>&
    operator>>(basic_istream<charT, Traits>& is,
               time_point<high_resolution_clock, Duration>& tp);

}  // chrono
}  // std

*/

#include <algorithm>
#include <chrono>
#include "ratio_io.h"

namespace std
{

namespace chrono
{

template <class To, class Rep, class Period>
To
round(const duration<Rep, Period>& d)
{
    To t0 = duration_cast<To>(d);
    To t1 = t0;
    ++t1;
    typedef typename common_type<To, duration<Rep, Period> >::type _D;
    _D diff0 = d - t0;
    _D diff1 = t1 - d;
    if (diff0 == diff1)
    {
        if (t0.count() & 1)
            return t1;
        return t0;
    }
    else if (diff0 < diff1)
        return t0;
    return t1;
}

enum duration_style {prefix, symbol};

// Added suffix enum to the name to make it compile
// under G++ without adding -fpermissive compiler flag.
enum timezone_enum {utc, local};

class durationpunct
    : public locale::facet
{
private:
    duration_style __style_;
public:
    static locale::id id;

    explicit durationpunct(size_t refs = 0)
        : locale::facet(refs), __style_(prefix) {}

    explicit durationpunct(duration_style fmt, size_t refs = 0)
        : locale::facet(refs), __style_(fmt) {}

    bool is_symbol_name() const {return __style_ == symbol;}
    bool is_prefix_name() const {return __style_ == prefix;}
};

class duration_fmt
{
    duration_style form_;
public:
    explicit duration_fmt(duration_style f) : form_(f) {}
#ifndef _MSC_VER
    explicit
#endif
        operator duration_style() const {return form_;}
};

template<class charT, class traits>
basic_ostream<charT, traits>&
operator <<(basic_ostream<charT, traits>& os, duration_fmt d)
{
    os.imbue(locale(os.getloc(), new durationpunct(static_cast<duration_style>(d))));
    return os;
}

template<class charT, class traits>
basic_istream<charT, traits>&
operator >>(basic_istream<charT, traits>& is, duration_fmt d)
{
    is.imbue(locale(is.getloc(), new durationpunct(static_cast<duration_style>(d))));
    return is;
}

template <class _CharT, class _Rep, class _Period>
basic_string<_CharT>
__get_unit(bool __is_long, const duration<_Rep, _Period>& d)
{
    if (__is_long)
    {
        _CharT __p[] = {'s', 'e', 'c', 'o', 'n', 'd', 's', 0};
        basic_string<_CharT> s = ratio_string<_Period, _CharT>::prefix() + __p;
        if (d.count() == 1 || d.count() == -1)
            s.pop_back();
        return s;
    }
    return ratio_string<_Period, _CharT>::symbol() + 's';
}

template <class _CharT, class _Rep>
basic_string<_CharT>
__get_unit(bool __is_long, const duration<_Rep, ratio<1> >& d)
{
    if (__is_long)
    {
        _CharT __p[] = {'s', 'e', 'c', 'o', 'n', 'd', 's'};
        basic_string<_CharT> s = basic_string<_CharT>(__p, __p + sizeof(__p) / sizeof(_CharT));
        if (d.count() == 1 || d.count() == -1)
            s.pop_back();
        return s;
    }
    return basic_string<_CharT>(1, 's');
}

template <class _CharT, class _Rep>
basic_string<_CharT>
__get_unit(bool __is_long, const duration<_Rep, ratio<60> >& d)
{
    if (__is_long)
    {
        _CharT __p[] = {'m', 'i', 'n', 'u', 't', 'e', 's'};
        basic_string<_CharT> s = basic_string<_CharT>(__p, __p + sizeof(__p) / sizeof(_CharT));
        if (d.count() == 1 || d.count() == -1)
            s.pop_back();
        return s;
    }
    _CharT __p[] = {'m', 'i', 'n'};
    return basic_string<_CharT>(__p, __p + sizeof(__p) / sizeof(_CharT));
}

template <class _CharT, class _Rep>
basic_string<_CharT>
__get_unit(bool __is_long, const duration<_Rep, ratio<3600> >& d)
{
    if (__is_long)
    {
        _CharT __p[] = {'h', 'o', 'u', 'r', 's'};
        basic_string<_CharT> s = basic_string<_CharT>(__p, __p + sizeof(__p) / sizeof(_CharT));
        if (d.count() == 1 || d.count() == -1)
            s.pop_back();
        return s;
    }
    return basic_string<_CharT>(1, 'h');
}

template <class _CharT, class _Traits, class _Rep, class _Period>
basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os, const duration<_Rep, _Period>& __d)
{
    typename basic_ostream<_CharT, _Traits>::sentry ok(__os);
    if (ok)
    {
        typedef durationpunct _F;
        typedef basic_string<_CharT> string_type;
        bool failed = false;
        try
        {
            bool __is_long = true;
            locale __loc = __os.getloc();
            if (has_facet<_F>(__loc))
            {
                const _F& f = use_facet<_F>(__loc);
                __is_long = f.is_prefix_name();
            }
            string_type __unit = __get_unit<_CharT>(__is_long, __d);
            __os << __d.count() << ' ' << __unit;
        }
        catch (...)
        {
            failed = true;
        }
        if (failed)
            __os.setstate(ios_base::failbit | ios_base::badbit);
    }
    return __os;
}

template <class _Rep, bool = is_scalar<_Rep>::value>
struct __duration_io_intermediate
{
    typedef _Rep type;
};

template <class _Rep>
struct __duration_io_intermediate<_Rep, true>
{
    typedef typename conditional
    <
        is_floating_point<_Rep>::value,
            long double,
            typename conditional
            <
                is_signed<_Rep>::value,
                    long long,
                    unsigned long long
            >::type
    >::type type;
};

template <class T>
T
__gcd(T x, T y)
{
    while (y != 0)
    {
        T old_x = x;
        x = y;
        y = old_x % y;
    }
    return x;
}

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif

template <>
long double
inline
__gcd(long double x, long double y)
{
    return 1;
}

#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

template <class _CharT, class _Traits, class _Rep, class _Period>
basic_istream<_CharT, _Traits>&
operator>>(basic_istream<_CharT, _Traits>& __is, duration<_Rep, _Period>& __d)
{
    typedef basic_string<_CharT> string_type;
    typedef durationpunct _F;
    typedef typename __duration_io_intermediate<_Rep>::type _IR;
    _IR __r;
    // read value into __r
    __is >> __r;
    if (__is.good())
    {
        // now determine unit
        typedef istreambuf_iterator<_CharT, _Traits> _I;
        _I __i(__is);
        _I __e;
        if (__i != __e && *__i == ' ')  // mandatory ' ' after value
        {
            ++__i;
            if (__i != __e)
            {
                locale __loc = __is.getloc();
                // unit is num / den (yet to be determined)
                unsigned long long num = 0;
                unsigned long long den = 0;
                ios_base::iostate __err = ios_base::goodbit;
                if (*__i == '[')
                {
                    // parse [N/D]s or [N/D]seconds format
                    ++__i;
                    _CharT __x;
                    __is >> num >> __x >> den;
                    if (!__is.good() || __x != '/')
                    {
                        __is.setstate(__is.failbit);
                        return __is;
                    }
                    __i = _I(__is);
                    if (*__i != ']')
                    {
                        __is.setstate(__is.failbit);
                        return __is;
                    }
                    ++__i;
                    const basic_string<_CharT> __units[] =
                    {
                        __get_unit<_CharT>(true, seconds(2)),
                        __get_unit<_CharT>(true, seconds(1)),
                        __get_unit<_CharT>(false, seconds(1))
                    };
                    const basic_string<_CharT>* __k = __scan_keyword(__i, __e,
                                  __units, __units + sizeof(__units)/sizeof(__units[0]),
                                  use_facet<ctype<_CharT> >(__loc),
                                  __err);
                    switch ((__k - __units) / 3)
                    {
                    case 0:
                        break;
                    default:
                        __is.setstate(__err);
                        return __is;
                    }
                }
                else
                {
                    // parse SI name, short or long
                    const basic_string<_CharT> __units[] =
                    {
                        __get_unit<_CharT>(true, duration<_Rep, atto>(2)),
                        __get_unit<_CharT>(true, duration<_Rep, atto>(1)),
                        __get_unit<_CharT>(false, duration<_Rep, atto>(1)),
                        __get_unit<_CharT>(true, duration<_Rep, femto>(2)),
                        __get_unit<_CharT>(true, duration<_Rep, femto>(1)),
                        __get_unit<_CharT>(false, duration<_Rep, femto>(1)),
                        __get_unit<_CharT>(true, duration<_Rep, pico>(2)),
                        __get_unit<_CharT>(true, duration<_Rep, pico>(1)),
                        __get_unit<_CharT>(false, duration<_Rep, pico>(1)),
                        __get_unit<_CharT>(true, duration<_Rep, nano>(2)),
                        __get_unit<_CharT>(true, duration<_Rep, nano>(1)),
                        __get_unit<_CharT>(false, duration<_Rep, nano>(1)),
                        __get_unit<_CharT>(true, duration<_Rep, micro>(2)),
                        __get_unit<_CharT>(true, duration<_Rep, micro>(1)),
                        __get_unit<_CharT>(false, duration<_Rep, micro>(1)),
                        __get_unit<_CharT>(true, duration<_Rep, milli>(2)),
                        __get_unit<_CharT>(true, duration<_Rep, milli>(1)),
                        __get_unit<_CharT>(false, duration<_Rep, milli>(1)),
                        __get_unit<_CharT>(true, duration<_Rep, centi>(2)),
                        __get_unit<_CharT>(true, duration<_Rep, centi>(1)),
                        __get_unit<_CharT>(false, duration<_Rep, centi>(1)),
                        __get_unit<_CharT>(true, duration<_Rep, deci>(2)),
                        __get_unit<_CharT>(true, duration<_Rep, deci>(1)),
                        __get_unit<_CharT>(false, duration<_Rep, deci>(1)),
                        __get_unit<_CharT>(true, duration<_Rep, deca>(2)),
                        __get_unit<_CharT>(true, duration<_Rep, deca>(1)),
                        __get_unit<_CharT>(false, duration<_Rep, deca>(1)),
                        __get_unit<_CharT>(true, duration<_Rep, hecto>(2)),
                        __get_unit<_CharT>(true, duration<_Rep, hecto>(1)),
                        __get_unit<_CharT>(false, duration<_Rep, hecto>(1)),
                        __get_unit<_CharT>(true, duration<_Rep, kilo>(2)),
                        __get_unit<_CharT>(true, duration<_Rep, kilo>(1)),
                        __get_unit<_CharT>(false, duration<_Rep, kilo>(1)),
                        __get_unit<_CharT>(true, duration<_Rep, mega>(2)),
                        __get_unit<_CharT>(true, duration<_Rep, mega>(1)),
                        __get_unit<_CharT>(false, duration<_Rep, mega>(1)),
                        __get_unit<_CharT>(true, duration<_Rep, giga>(2)),
                        __get_unit<_CharT>(true, duration<_Rep, giga>(1)),
                        __get_unit<_CharT>(false, duration<_Rep, giga>(1)),
                        __get_unit<_CharT>(true, duration<_Rep, tera>(2)),
                        __get_unit<_CharT>(true, duration<_Rep, tera>(1)),
                        __get_unit<_CharT>(false, duration<_Rep, tera>(1)),
                        __get_unit<_CharT>(true, duration<_Rep, peta>(2)),
                        __get_unit<_CharT>(true, duration<_Rep, peta>(1)),
                        __get_unit<_CharT>(false, duration<_Rep, peta>(1)),
                        __get_unit<_CharT>(true, duration<_Rep, exa>(2)),
                        __get_unit<_CharT>(true, duration<_Rep, exa>(1)),
                        __get_unit<_CharT>(false, duration<_Rep, exa>(1)),
                        __get_unit<_CharT>(true, duration<_Rep, ratio<1> >(2)),
                        __get_unit<_CharT>(true, duration<_Rep, ratio<1> >(1)),
                        __get_unit<_CharT>(false, duration<_Rep, ratio<1> >(1)),
                        __get_unit<_CharT>(true, duration<_Rep, ratio<60> >(2)),
                        __get_unit<_CharT>(true, duration<_Rep, ratio<60> >(1)),
                        __get_unit<_CharT>(false, duration<_Rep, ratio<60> >(1)),
                        __get_unit<_CharT>(true, duration<_Rep, ratio<3600> >(2)),
                        __get_unit<_CharT>(true, duration<_Rep, ratio<3600> >(1)),
                        __get_unit<_CharT>(false, duration<_Rep, ratio<3600> >(1))
                    };
                    const basic_string<_CharT>* __k = __scan_keyword(__i, __e,
                                  __units, __units + sizeof(__units)/sizeof(__units[0]),
                                  use_facet<ctype<_CharT> >(__loc),
                                  __err);
                    switch (__k - __units)
                    {
                    case 0:
                    case 1:
                    case 2:
                        num = 1ULL;
                        den = 1000000000000000000ULL;
                        break;
                    case 3:
                    case 4:
                    case 5:
                        num = 1ULL;
                        den = 1000000000000000ULL;
                        break;
                    case 6:
                    case 7:
                    case 8:
                        num = 1ULL;
                        den = 1000000000000ULL;
                        break;
                    case 9:
                    case 10:
                    case 11:
                        num = 1ULL;
                        den = 1000000000ULL;
                        break;
                    case 12:
                    case 13:
                    case 14:
                        num = 1ULL;
                        den = 1000000ULL;
                        break;
                    case 15:
                    case 16:
                    case 17:
                        num = 1ULL;
                        den = 1000ULL;
                        break;
                    case 18:
                    case 19:
                    case 20:
                        num = 1ULL;
                        den = 100ULL;
                        break;
                    case 21:
                    case 22:
                    case 23:
                        num = 1ULL;
                        den = 10ULL;
                        break;
                    case 24:
                    case 25:
                    case 26:
                        num = 10ULL;
                        den = 1ULL;
                        break;
                    case 27:
                    case 28:
                    case 29:
                        num = 100ULL;
                        den = 1ULL;
                        break;
                    case 30:
                    case 31:
                    case 32:
                        num = 1000ULL;
                        den = 1ULL;
                        break;
                    case 33:
                    case 34:
                    case 35:
                        num = 1000000ULL;
                        den = 1ULL;
                        break;
                    case 36:
                    case 37:
                    case 38:
                        num = 1000000000ULL;
                        den = 1ULL;
                        break;
                    case 39:
                    case 40:
                    case 41:
                        num = 1000000000000ULL;
                        den = 1ULL;
                        break;
                    case 42:
                    case 43:
                    case 44:
                        num = 1000000000000000ULL;
                        den = 1ULL;
                        break;
                    case 45:
                    case 46:
                    case 47:
                        num = 1000000000000000000ULL;
                        den = 1ULL;
                        break;
                    case 48:
                    case 49:
                    case 50:
                        num = 1;
                        den = 1;
                        break;
                    case 51:
                    case 52:
                    case 53:
                        num = 60;
                        den = 1;
                        break;
                    case 54:
                    case 55:
                    case 56:
                        num = 3600;
                        den = 1;
                        break;
                    default:
                        __is.setstate(__err);
                        return __is;
                    }
                }
                // unit is num/den
                // __r should be multiplied by (num/den) / _Period
                // Reduce (num/den) / _Period to lowest terms
                unsigned long long __gcd_n1_n2 = __gcd<unsigned long long>(num, _Period::num);
                unsigned long long __gcd_d1_d2 = __gcd<unsigned long long>(den, _Period::den);
                num /= __gcd_n1_n2;
                den /= __gcd_d1_d2;
                unsigned long long __n2 = _Period::num / __gcd_n1_n2;
                unsigned long long __d2 = _Period::den / __gcd_d1_d2;
                if (num > numeric_limits<unsigned long long>::max() / __d2 ||
                    den > numeric_limits<unsigned long long>::max() / __n2)
                {
                    // (num/den) / _Period overflows
                    __is.setstate(__is.failbit);
                    return __is;
                }
                num *= __d2;
                den *= __n2;
                // num / den is now factor to multiply by __r
                typedef typename common_type<_IR, unsigned long long>::type _CT;
                if (is_integral<_IR>::value)
                {
                    // Reduce __r * num / den
                    _CT __t = __gcd<_CT>(__r, den);
                    __r /= __t;
                    den /= __t;
                    if (den != 1)
                    {
                        // Conversion to _Period is integral and not exact
                        __is.setstate(__is.failbit);
                        return __is;
                    }
                }
                if (__r > duration_values<_CT>::max() / num)
                {
                    // Conversion to _Period overflowed
                    __is.setstate(__is.failbit);
                    return __is;
                }
                _CT __t = __r * num;
                __t /= den;
                if (duration_values<_Rep>::max() < __t)
                {
                    // Conversion to _Period overflowed
                    __is.setstate(__is.failbit);
                    return __is;
                }
                // Success!  Store it.
                __r = _Rep(__t);
                __d = duration<_Rep, _Period>(__r);
                __is.setstate(__err);
            }
            else
                __is.setstate(__is.failbit | __is.eofbit);
        }
        else
        {
            if (__i == __e)
                __is.setstate(__is.eofbit);
            __is.setstate(__is.failbit);
        }
    }
    else
        __is.setstate(__is.failbit);
    return __is;
}

template <class charT>
class timepunct
    : public locale::facet
{
public:
    typedef basic_string<charT> string_type;

private:
    string_type           fmt_;
    chrono::timezone_enum tz_;

public:
    static locale::id id;

    explicit timepunct(size_t refs = 0)
        : locale::facet(refs), tz_(utc) {}
    timepunct(timezone_enum tz, string_type fmt, size_t refs = 0)
        : locale::facet(refs), fmt_(std::move(fmt)), tz_(tz) {}

    const string_type& fmt() const {return fmt_;}
    chrono::timezone_enum timezone() const {return tz_;}
};

template <class CharT>
locale::id
timepunct<CharT>::id;

template <class _CharT, class _Traits, class _Duration>
basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os,
           const time_point<steady_clock, _Duration>& __tp)
{
    return __os << __tp.time_since_epoch() << " since boot";
}

template<class charT>
struct __time_manip
{
    basic_string<charT> fmt_;
    timezone_enum tz_;

    __time_manip(timezone_enum tz, basic_string<charT> fmt)
        : fmt_(std::move(fmt)),
          tz_(tz) {}
};

template<class charT, class traits>
basic_ostream<charT, traits>&
operator <<(basic_ostream<charT, traits>& os, __time_manip<charT> m)
{
    os.imbue(locale(os.getloc(), new timepunct<charT>(m.tz_, std::move(m.fmt_))));
    return os;
}

template<class charT, class traits>
basic_istream<charT, traits>&
operator >>(basic_istream<charT, traits>& is, __time_manip<charT> m)
{
    is.imbue(locale(is.getloc(), new timepunct<charT>(m.tz_, std::move(m.fmt_))));
    return is;
}

template<class charT>
inline
__time_manip<charT>
time_fmt(timezone_enum tz, const charT* fmt)
{
    return __time_manip<charT>(tz, fmt);
}

template<class charT>
inline
__time_manip<charT>
time_fmt(timezone_enum tz, basic_string<charT> fmt)
{
    return __time_manip<charT>(tz, std::move(fmt));
}

class __time_man
{
    timezone_enum form_;
public:
    explicit __time_man(timezone_enum f) : form_(f) {}
    // explicit
        operator timezone_enum() const {return form_;}
};

template<class charT, class traits>
basic_ostream<charT, traits>&
operator <<(basic_ostream<charT, traits>& os, __time_man m)
{
    os.imbue(locale(os.getloc(), new timepunct<charT>(static_cast<timezone_enum>(m), basic_string<charT>())));
    return os;
}

template<class charT, class traits>
basic_istream<charT, traits>&
operator >>(basic_istream<charT, traits>& is, __time_man m)
{
    is.imbue(locale(is.getloc(), new timepunct<charT>(static_cast<timezone_enum>(m), basic_string<charT>())));
    return is;
}

inline
__time_man
time_fmt(timezone_enum f)
{
    return __time_man(f);
}

template <class _CharT, class _Traits, class _Duration>
basic_istream<_CharT, _Traits>&
operator>>(basic_istream<_CharT, _Traits>& __is,
           time_point<steady_clock, _Duration>& __tp)
{
    _Duration __d;
    __is >> __d;
    if (__is.good())
    {
        const _CharT __u[] = {' ', 's', 'i', 'n', 'c', 'e', ' ', 'b', 'o', 'o', 't'};
        const basic_string<_CharT> __units(__u, __u + sizeof(__u)/sizeof(__u[0]));
        ios_base::iostate __err = ios_base::goodbit;
        typedef istreambuf_iterator<_CharT, _Traits> _I;
        _I __i(__is);
        _I __e;
        ptrdiff_t __k = __scan_keyword(__i, __e,
                      &__units, &__units + 1,
                      use_facet<ctype<_CharT> >(__is.getloc()),
                      __err) - &__units;
        if (__k == 1)
        {
            // failed to read epoch string
            __is.setstate(__err);
            return __is;
        }
        __tp = time_point<steady_clock, _Duration>(__d);
    }
    else
        __is.setstate(__is.failbit);
    return __is;
}

template <class _CharT, class _Traits, class _Duration>
basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os,
           const time_point<system_clock, _Duration>& __tp)
{
    typename basic_ostream<_CharT, _Traits>::sentry ok(__os);
    if (ok)
    {
        bool failed = false;
        try
        {
            const _CharT* pb = nullptr;
            const _CharT* pe = pb;
            timezone_enum tz = utc;
            typedef timepunct<_CharT> F;
            locale loc = __os.getloc();
            if (has_facet<F>(loc))
            {
                const F& f = use_facet<F>(loc);
                pb = f.fmt().data();
                pe = pb + f.fmt().size();
                tz = f.timezone();
            }
            time_t __t = system_clock::to_time_t(__tp);
            tm __tm;
            if (tz == local)
            {
                if (localtime_r(&__t, &__tm) == 0)
                    failed = true;
            }
            else
            {
                if (gmtime_r(&__t, &__tm) == 0)
                    failed = true;
            }
            if (!failed)
            {
                const time_put<_CharT>& tp = use_facet<time_put<_CharT> >(loc);
                if (pb == pe)
                {
                    _CharT pattern[] = {'%', 'F', 'T', '%', 'H', ':', '%', 'M', ':'};
                    pb = pattern;
                    pe = pb + sizeof(pattern) / sizeof(_CharT);
                    failed = tp.put(__os, __os, __os.fill(), &__tm, pb, pe).failed();
                    if (!failed)
                    {
                        duration<double> __d = __tp - system_clock::from_time_t(__t) +
                                  seconds(__tm.tm_sec);
                        if (__d.count() < 10)
                            __os << _CharT('0');
                        ios::fmtflags __flgs = __os.flags();
                        __os.setf(ios::fixed, ios::floatfield);
                        __os << __d.count();
                        __os.flags(__flgs);
                        if (tz == local)
                        {
                            _CharT sub_pattern[] = {' ', '%', 'z'};
                            pb = sub_pattern;
                            pe = pb + + sizeof(sub_pattern) / sizeof(_CharT);
                            failed = tp.put(__os, __os, __os.fill(), &__tm, pb, pe).failed();
                        }
                        else
                        {
                            _CharT sub_pattern[] = {' ', '+', '0', '0', '0', '0', 0};
                            __os << sub_pattern;
                        }
                    }
                }
                else
                    failed = tp.put(__os, __os, __os.fill(), &__tm, pb, pe).failed();
            }
        }
        catch (...)
        {
            failed = true;
        }
        if (failed)
            __os.setstate(ios_base::failbit | ios_base::badbit);
    }
    return __os;
}

template <class _CharT, class _InputIterator>
minutes
__extract_z(_InputIterator& __b, _InputIterator __e,
            ios_base::iostate& __err, const ctype<_CharT>& __ct)
{
    int __minutes = 0;
    if (__b != __e)
    {
        char __cn = __ct.narrow(*__b, 0);
        if (__cn != '+' && __cn != '-')
        {
            __err |= ios_base::failbit;
            return minutes(0);
        }
        int __sn = __cn == '-' ? -1 : 1;
        int __hr = 0;
        for (int i = 0; i < 2; ++i)
        {
            if (++__b == __e)
            {
                __err |= ios_base::eofbit | ios_base::failbit;
                return minutes(0);
            }
            __cn = __ct.narrow(*__b, 0);
            if (!('0' <= __cn && __cn <= '9'))
            {
                __err |= ios_base::failbit;
                return minutes(0);
            }
            __hr = __hr * 10 + __cn - '0';
        }
        for (int i = 0; i < 2; ++i)
        {
            if (++__b == __e)
            {
                __err |= ios_base::eofbit | ios_base::failbit;
                return minutes(0);
            }
            __cn = __ct.narrow(*__b, 0);
            if (!('0' <= __cn && __cn <= '9'))
            {
                __err |= ios_base::failbit;
                return minutes(0);
            }
            __minutes = __minutes * 10 + __cn - '0';
        }
        if (++__b == __e)
            __err |= ios_base::eofbit;
        __minutes += __hr * 60;
        __minutes *= __sn;
    }
    else
        __err |= ios_base::eofbit | ios_base::failbit;
    return minutes(__minutes);
}

template <class _CharT, class _Traits, class _Duration>
basic_istream<_CharT, _Traits>&
operator>>(basic_istream<_CharT, _Traits>& __is,
           time_point<system_clock, _Duration>& __tp)
{
    typename basic_istream<_CharT,_Traits>::sentry ok(__is);
    if (ok)
    {
        ios_base::iostate err = ios_base::goodbit;
        try
        {
            const _CharT* pb = nullptr;
            const _CharT* pe = pb;
            typedef timepunct<_CharT> F;
            locale loc = __is.getloc();
            timezone_enum tz = utc;
            if (has_facet<F>(loc))
            {
                const F& f = use_facet<F>(loc);
                pb = f.fmt().data();
                pe = pb + f.fmt().size();
                tz = f.timezone();
            }
            const time_get<_CharT>& tg = use_facet<time_get<_CharT> >(loc);
            const ctype<_CharT>& __ct = use_facet<ctype<_CharT> >(loc);
            tm __tm = {0};
            typedef istreambuf_iterator<_CharT, _Traits> _I;
            if (pb == pe)
            {
                _CharT pattern[] = {'%', 'Y', '-', '%', 'm', '-', '%', 'd',
                                    'T', '%', 'H', ':', '%', 'M', ':'};
                pb = pattern;
                pe = pb + sizeof(pattern) / sizeof(_CharT);
                tg.get(__is, 0, __is, err, &__tm, pb, pe);
                if (err & ios_base::failbit)
                    goto __exit;
                double __sec;
                _CharT __c = _CharT();
                __is >> __sec;
                if (__is.fail())
                {
                    err |= ios_base::failbit;
                    goto __exit;
                }
                _I __i(__is);
                _I __eof;
                __c = *__i;
                if (++__i == __eof || __c != ' ')
                {
                    err |= ios_base::failbit;
                    goto __exit;
                }
                minutes __minutes = __extract_z(__i, __eof, err, __ct);
                if (err & ios_base::failbit)
                    goto __exit;
                time_t __t;
                __t = timegm(&__tm);
                __tp = system_clock::from_time_t(__t) - __minutes
                                 + round<microseconds>(duration<double>(__sec));
            }
            else
            {
                const _CharT __z[2] = {'%', 'z'};
                const _CharT* __fz = std::search(pb, pe, __z, __z+2);
                tg.get(__is, 0, __is, err, &__tm, pb, __fz);
                minutes __minutes(0);
                if (__fz != pe)
                {
                    if (err != ios_base::goodbit)
                    {
                        err |= ios_base::failbit;
                        goto __exit;
                    }
                    _I __i(__is);
                    _I __eof;
                    __minutes = __extract_z(__i, __eof, err, __ct);
                    if (err & ios_base::failbit)
                        goto __exit;
                    if (__fz+2 != pe)
                    {
                        if (err != ios_base::goodbit)
                        {
                            err |= ios_base::failbit;
                            goto __exit;
                        }
                        tg.get(__is, 0, __is, err, &__tm, __fz+2, pe);
                        if (err & ios_base::failbit)
                            goto __exit;
                    }
                }
                __tm.tm_isdst = -1;
                time_t __t;
                if (tz == utc || __fz != pe)
                    __t = timegm(&__tm);
                else
                    __t = mktime(&__tm);
                __tp = system_clock::from_time_t(__t) - __minutes;
            }
        }
        catch (...)
        {
            err |= ios_base::badbit | ios_base::failbit;
        }
    __exit:
        __is.setstate(err);
    }
    return __is;
}

}  // chrono

} // std

#endif  // _CHRONO_IO
